package com.qingyun.edusysteam.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingyun.edusysteam.dto.MaterialDTO;
import com.qingyun.edusysteam.dto.Result;
import com.qingyun.edusysteam.dto.UserDTO;
import com.qingyun.edusysteam.entity.Material;
import com.qingyun.edusysteam.mapper.MaterialMapper;
import com.qingyun.edusysteam.service.IMaterialService;
import com.qingyun.edusysteam.utils.FileUploadUtil;
import com.qingyun.edusysteam.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import static com.qingyun.edusysteam.utils.RedisConstants.LOGIN_USER_KEY;

/**
 * <p>
 * 资料中心 服务实现类
 * </p>
 *
 * @author your_name
 * @since 2025-08-23
 */
@Service
@Slf4j
public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> implements IMaterialService {

    @Autowired
    private MaterialMapper materialMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private FileUploadUtil fileUploadUtil;
    @Autowired
    private UserHolder userHolder;
    @Override
    public Result uploadMaterial(MaterialDTO materialDTO, String token) {
        try {

            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }

            // 2. 处理上传的文件
            MultipartFile file = materialDTO.getFile();
            if (file == null || file.isEmpty()) {
                return Result.fail("上传文件不能为空");
            }
            
            String relativeFilePath = fileUploadUtil.uploadFile(file); // 获取文件相对路径

            // 3. 转换DTO到实体，并补充文件相关信息
            Material material = new Material();
            material.setTitle(materialDTO.getTitle());
            material.setDescription(materialDTO.getDescription());
            material.setCategory(materialDTO.getCategory());
            material.setGrade(materialDTO.getGrade());
            material.setSubject(materialDTO.getSubject());

            // 补充文件元信息
            material.setOriginalFileName(file.getOriginalFilename()); // 原始文件名
            material.setFilePath(relativeFilePath); // 存储路径（相对路径）
            material.setFileSize(file.getSize()); // 文件大小（字节）
            material.setMimeType(file.getContentType()); // MIME类型

            // 4. 补充其他必填字段
            material.setUploaderId(userId); // 上传者ID
            material.setStatus(1); // 状态：1有效
            material.setDownloadCount(0); // 初始下载次数为0
            // createTime和updateTime由数据库自动生成，无需手动设置

            // 5. 保存到数据库
            materialMapper.insert(material);

            return Result.ok(material.getId());

        } catch (IllegalArgumentException e) {
            return Result.fail(e.getMessage());
        } catch (IOException e) {
            return Result.fail("文件存储失败：" + e.getMessage());
        } catch (Exception e) {
            return Result.fail("上传失败：" + e.getMessage());
        }
    }

    @Override
    public Result downloadMaterial(Long id, String token, HttpServletResponse response) {
        try {
            // 1. 验证用户登录状态
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }

            // 2. 查询资料信息
            Material material = materialMapper.selectById(id);
            if (material == null) {
                throw new RuntimeException("资料不存在");
            }
            
            if (material.getStatus() == 0) {
                throw new RuntimeException("资料已被删除");
            }

            // 3. 构建文件路径
            String fullFilePath = fileUploadUtil.getFullPath(material.getFilePath());
            File file = new File(fullFilePath);
            
            if (!file.exists()) {
                throw new RuntimeException("文件不存在");
            }

            // 4. 设置响应头
            response.setContentType(material.getMimeType());
            response.setContentLengthLong(material.getFileSize());
            
            // 设置文件名编码，支持中文
            String fileName = material.getOriginalFileName();
            if (StrUtil.isNotBlank(fileName)) {
                String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
                response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
            }

            // 5. 写入文件流
            try (FileInputStream fis = new FileInputStream(file);
                 OutputStream os = response.getOutputStream()) {
                
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = fis.read(buffer)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
                os.flush();
            }

            // 6. 更新下载次数
            LambdaUpdateWrapper<Material> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Material::getId, id)
                        .setSql("download_count = download_count + 1");
            materialMapper.update(null, updateWrapper);
        } catch (Exception e) {
            throw new RuntimeException("下载失败：" + e.getMessage());
        }
        return Result.ok();
    }

    @Override
    public Result getMaterialList(String category, String grade, String keyword, String token, String subject) {
        try {
            log.info("调用获取信息接口");
            // 1. 验证用户登录状态
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户信息获取失败");
            }

            // 3. 构建查询条件
            LambdaQueryWrapper<Material> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Material::getUploaderId, userId) // 只查询当前用户的资料
                        .eq(Material::getStatus, 1); // 只查询有效资料
            
            // 添加筛选条件
            if (StrUtil.isNotBlank(category)) {
                queryWrapper.eq(Material::getCategory, category);
            }
            if (StrUtil.isNotBlank(grade)) {
                queryWrapper.eq(Material::getGrade, grade);
            }
            if (StrUtil.isNotBlank(keyword)) {
                queryWrapper.like(Material::getTitle, keyword);
            }
            if (StrUtil.isNotBlank(subject)) {
                queryWrapper.eq(Material::getSubject, subject);
            }
            
            // 按创建时间倒序排列
            queryWrapper.orderByDesc(Material::getCreateTime);

            // 4. 执行查询
            List<Material> materials = materialMapper.selectList(queryWrapper);

            return Result.ok(materials);

        } catch (Exception e) {
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @Override
    public Result getDownloadableMaterials(String category, String grade, String keyword, String token, String subject) {
        try {
            log.info("调用获取可下载资料接口");
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }

            // 2. 构建查询条件 - 查询所有有效的资料，不限制上传者
            LambdaQueryWrapper<Material> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Material::getStatus, 1); // 只查询有效资料
            
            // 添加筛选条件
            if (StrUtil.isNotBlank(category)) {
                queryWrapper.eq(Material::getCategory, category);
            }
            if (StrUtil.isNotBlank(grade)) {
                queryWrapper.eq(Material::getGrade, grade);
            }
            if (StrUtil.isNotBlank(keyword)) {
                queryWrapper.like(Material::getTitle, keyword);
            }
            if (StrUtil.isNotBlank(subject)) {
                queryWrapper.eq(Material::getSubject, subject);
            }
            
            // 按创建时间倒序排列
            queryWrapper.orderByDesc(Material::getCreateTime);

            // 3. 执行查询
            List<Material> materials = materialMapper.selectList(queryWrapper);

            return Result.ok(materials);

        } catch (Exception e) {
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @Override
    public Result deleteMaterial(Long id, String token) {
        try {
            // 1. 验证用户登录状态
            String userInfoKey = LOGIN_USER_KEY + token;
            Boolean hasKey = stringRedisTemplate.hasKey(userInfoKey);
            if (BooleanUtil.isFalse(hasKey)) {
                return Result.fail("用户未登录或登录已过期");
            }

            // 2. 获取用户信息
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }


            // 3. 查询资料信息
            Material material = materialMapper.selectById(id);
            if (material == null) {
                return Result.fail("资料不存在");
            }
            
            // 4. 验证权限（只能删除自己的资料）
            if (!material.getUploaderId().equals(userId)) {
                return Result.fail("无权限删除此资料");
            }

            // 5. 软删除（更新状态为0）
            LambdaUpdateWrapper<Material> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Material::getId, id)
                        .set(Material::getStatus, 0);
            
            int result = materialMapper.update(null, updateWrapper);
            if (result > 0) {
                return Result.ok("删除成功");
            } else {
                return Result.fail("删除失败");
            }

        } catch (Exception e) {
            return Result.fail("删除失败：" + e.getMessage());
        }
    }
}
